package com.java.agent;

import com.java.agent.interceptor.MethodExcuteCost;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.instrument.Instrumentation;
import java.util.jar.JarFile;

/**
 * premain 有两个参数的  premain(String agentArgs, Instrumentation instrumentation)
 * 还有一个参数的 写法为 premain(String agentArgs）
 * 当两个方法都存在的时候 默认调用两个参数的方法 。当只有一个参数的方法存在时，调用一个参数的方法。
 *
 * @author dushougudu
 */
public class PreMainAgent {

    /**
     * @param agentArgs
     * @param instrumentation 个是java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口 也是这个包的核心
     *                        集中了其中几乎所有的功能方法，例如类定义的转换和操作等
     */
    public static void premain(String agentArgs, Instrumentation instrumentation) {
        // ByteBuddy对java agent 提供了转换器的实现 为AgentBuilder.Transformer
        AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
            // builder.method 指定哪些方法被拦截  需要ElementMatchers类型的参数
            // ElementMatchers.isAnnotatedWith(MethodCost.class) 方法被拦截
            // intercept 自定义拦截器 需要MethodDelegation类型的参数
            return builder.method(ElementMatchers.any())
                    //我们自定义的拦截器类
                    .intercept(MethodDelegation.to(MethodExcuteCost.class));
        };
        //创建完拦截器后 通过ByteBuddy的AgentBuilder创建者来构建 agent 对象 指定拦截的类型 同时还需要指定转换器对象
        // type属性 指定拦截的类型 的类都拦截
        new AgentBuilder.Default().type(ElementMatchers.nameContains("Controller"))
                // 传入上面我们创建的转换器 将拦截到的类交给transformer来处理
                // installOn 将该方法 加载到 Instrumentation 让他根据我们的配置生效
                .transform(transformer).installOn(instrumentation);
    }

    public static void agentmain(String agentArgs, Instrumentation instrumentation) {
        premain(agentArgs, instrumentation);
    }


    /**
     * 动态加载jar到 BootstrapClassLoade/SystemClassLoader
     *
     * @param instrumentation
     * @param jarFile
     */
    public void appendToSystemClassLoaderSearch(Instrumentation instrumentation, JarFile jarFile) {
        instrumentation.appendToSystemClassLoaderSearch(jarFile);
    }

//    public void attachVM() throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
//        List<VirtualMachineDescriptor> list = VirtualMachine.list();
//        for (VirtualMachineDescriptor vmd : list) {
//            if (vmd.displayName().endsWith("com.rickiyang.learn.job.TestAgentMain")) {
//                VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
//                virtualMachine.loadAgent("/Users/yangyue/Documents/java-agent.jar");
//                virtualMachine.detach();
//            }
//        }
//    }

}